home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / ODF Release 3 / ODFDev / ODF / Found / FWString / SLStrRep.cpp < prev    next >
Encoding:
Text File  |  1996-12-16  |  49.4 KB  |  1,670 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLStrRep.cpp
  4. //    Release Version:    $ ODF 3 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFound.hpp"
  11.  
  12. #ifndef PRSTRREP_H
  13. #include "PRStrRep.h"
  14. #endif
  15.  
  16. #ifndef SLPRIDEB_H
  17. #include "SLPriDeb.h"
  18. #endif
  19.  
  20. #ifndef SLPRIMEM_H
  21. #include "SLPriMem.h"
  22. #endif
  23.  
  24. // ----- Foundation Includes -----
  25.  
  26. #ifndef FWPRIDEB_H
  27. #include "FWPriDeb.h"
  28. #endif
  29.  
  30. #ifdef FW_BUILD_MAC
  31. #include <OSA.h>
  32. #endif
  33.  
  34. #ifdef FW_BUILD_MAC
  35. #include <Script.h>
  36. #endif
  37.  
  38. #ifndef _ERRORDEF_
  39. #include "ErrorDef.xh"
  40. #endif
  41.  
  42. #ifdef FW_BUILD_MAC
  43. #include <TextUtils.h>
  44. #endif
  45.  
  46. #ifdef FW_BUILD_MAC
  47. #include <fp.h>
  48. #endif
  49.  
  50. #ifdef FW_BUILD_WIN
  51. // include for GetACP
  52. #include <winnls.h>
  53. #endif
  54.  
  55. #ifdef FW_BUILD_MAC
  56. #pragma segment Strings
  57. #endif
  58.  
  59. //========================================================================================
  60. //    Platform-dependent constant kTraditionalTextFormat
  61. //========================================================================================
  62. #ifdef FW_BUILD_MAC
  63. #define kTraditionalTextFormat    kODTraditionalMacText
  64. #endif
  65.  
  66. #ifdef FW_BUILD_WIN
  67.     // Include OpenDoc for Windows file that defines kODIBMCodePageText
  68.     #ifndef SOM_Module_include5cStdDefs_OpenDoc_StdDefs_defined
  69.     #include <StdDefs.xh>
  70.     #endif
  71. #define kTraditionalTextFormat    kODIBMCodePageText
  72. #endif
  73.  
  74. //========================================================================================
  75. //    gEmptyStringRep
  76. //========================================================================================
  77.  
  78. static FW_Locale gDefaultLocaleData = 
  79. {
  80. #ifdef FW_BUILD_MAC
  81.     smRoman,        // fScriptCode
  82.     langEnglish        // fLangCode
  83. #endif
  84. #ifdef FW_BUILD_WIN
  85.     FW_kWinLatin1,    // Latin1 code page, defined in SLLocale.h
  86.     0                // not used
  87. #endif
  88. };
  89.  
  90. static FW_SPrivStringRep gEmptyStringRep = 
  91. {
  92.     {    // ODIText fText;
  93.         kTraditionalTextFormat,            // format
  94.         {
  95.             sizeof(gDefaultLocaleData),    // _maximum
  96.             sizeof(gDefaultLocaleData),    // _length
  97.             (unsigned char*) &gDefaultLocaleData            // _buffer
  98.         }
  99.     },
  100.     {    // FW_ODITextParams    fParams;
  101.         (char*) &gDefaultLocaleData+sizeof(gDefaultLocaleData),    // fTextStart
  102.         0,                                // fTextByteLength
  103.         0                                // fTextByteCapacity
  104.     },
  105.     100,                                // fRefCount
  106.     false                                // fLocked
  107. };
  108.  
  109. //----------------------------------------------------------------------------------------
  110. //    FW_PrivInitStringData - call once after static initialization
  111. //----------------------------------------------------------------------------------------
  112.  
  113. void FW_PrivInitStringData()
  114. {
  115.     // Set the gDefaultLocaleData to the system script and language
  116. #ifdef FW_BUILD_MAC
  117.     gDefaultLocaleData.fScriptCode = ::GetScriptManagerVariable(smSysScript);
  118.     gDefaultLocaleData.fLangCode = ::GetScriptVariable(gDefaultLocaleData.fScriptCode, smScriptLang);
  119. #endif    
  120. #ifdef FW_BUILD_WIN
  121.     // Set the gDefaultLocaleData to the current ANSI code-page identifier for the system
  122.     gDefaultLocaleData.fScriptCode = ::GetACP();
  123. #endif    
  124. }
  125.  
  126. //----------------------------------------------------------------------------------------
  127. //    FW_PrivGetDefaultLocale - return default (system) locale
  128. //----------------------------------------------------------------------------------------
  129.  
  130. FW_Locale FW_PrivGetDefaultLocale()
  131. {
  132.     return gDefaultLocaleData;
  133. }
  134.  
  135. //========================================================================================
  136. //    FW_SPrivStringRep Functions
  137. //========================================================================================
  138.  
  139. //----------------------------------------------------------------------------------------
  140. //    FW_Check
  141. //----------------------------------------------------------------------------------------
  142.  
  143.  
  144. #ifdef FW_DEBUG
  145.     static void FW_Check(FW_HString self, long minRefCount)
  146.     {
  147.         // No need for FW_ERR_TRY block
  148.         FW_PlatformError error;
  149.         FW_PRIV_ASSERT(self);
  150.         FW_PRIV_ASSERT(self->fRefCount>=minRefCount);
  151.         FW_PRIV_ASSERT(0 <= self->fText.text._length);
  152.         FW_PRIV_ASSERT(self->fText.text._length <= self->fText.text._maximum);
  153.         FW_PRIV_ASSERT(self->fText.text._buffer!=0);
  154.  
  155.         FW_ODITextParams params;
  156.         FW_TextParams_GetParams(&self->fText, ¶ms, &error);
  157.         FW_PRIV_ASSERT(error == 0);
  158.         FW_PRIV_ASSERT(self->fParams.fTextStart == params.fTextStart);
  159.         FW_PRIV_ASSERT(self->fParams.fTextByteLength == params.fTextByteLength);
  160.         FW_PRIV_ASSERT(self->fParams.fTextByteCapacity == params.fTextByteCapacity);
  161.         FW_PRIV_ASSERT(self->fParams.fTextByteLength <= self->fParams.fTextByteCapacity);
  162.     }
  163.     #define FW_CHECK(self) FW_Check(self, 1);
  164. #else
  165.     #define FW_CHECK(self)
  166. #endif
  167.  
  168. #if    defined(FW_DEBUG) && defined(FW_BUILD_MAC)
  169. #define CHECK_ERROR if (*error) { Debugger(); return 0; } else 0
  170. #else
  171. #define CHECK_ERROR if (*error) { return 0; } else 0
  172. #endif
  173.  
  174. //----------------------------------------------------------------------------------------
  175. //    StringRep_Clone
  176. //----------------------------------------------------------------------------------------
  177. // Conditionally creates a copy.  If the reference count of the
  178. // self is exactly one, or if self is locked, then self is simply returned, unchanged.
  179. // If the reference count of self is greater than one, then 
  180. // its contents are cloned, and self's reference count is decremented.
  181. // The reference count of the copy is set to 1.
  182. // Note that this function conserves the total reference count.
  183.  
  184. static FW_HString StringRep_Clone(FW_HString self, FW_PlatformError *error);
  185.  
  186. static FW_HString StringRep_Clone(FW_HString self, FW_PlatformError *error)
  187. {
  188.     *error = 0;
  189.     FW_CHECK(self);
  190.     
  191.     FW_PRIV_ASSERT(self->fRefCount>=1);
  192.     FW_HString clone = self;
  193.     
  194.     if ((!self->fLocked) && (self->fRefCount > 1))
  195.     {            
  196.         clone = (FW_SPrivStringRep*)::FW_PrimitiveAllocateBlock(sizeof(FW_SPrivStringRep));
  197.         if (clone == NULL)
  198.         {
  199.             *error = kODErrOutOfMemory;
  200.             return 0;
  201.         }
  202.         
  203.         *clone = *self;
  204.         clone->fRefCount = 0;
  205.         clone->fText.text._buffer = (unsigned char*)
  206.                         ::FW_PrimitiveAllocateBlock(self->fText.text._maximum);
  207.         if (clone->fText.text._buffer == NULL)
  208.         {
  209.             *error = kODErrOutOfMemory;
  210.             return 0;
  211.         }
  212.  
  213.         ::FW_PrimitiveCopyMemory(self->fText.text._buffer,
  214.                             clone->fText.text._buffer,
  215.                             self->fText.text._length);
  216.         ::FW_TextParams_GetParams(&clone->fText, &clone->fParams, error);
  217.         CHECK_ERROR;
  218.         ::FW_PrivString_Acquire(clone);
  219.         ::FW_PrivString_Release(self);
  220.     }
  221.     
  222.     FW_CHECK(clone);
  223.     
  224.     return clone;
  225. }
  226.  
  227. //----------------------------------------------------------------------------------------
  228. //    FW_PrivString_NewRepWithStaticBuffer
  229. //----------------------------------------------------------------------------------------
  230.  
  231. FW_HString FW_PrivString_NewRepWithStaticBuffer(unsigned char* buffer,
  232.                                     FW_ByteCount bufferLen)
  233. {
  234.     // This function is obsolete and is here for compatibility with parts compiled
  235.     // with ODF Release 1 or Release 2. This function was called when an FW_CString32
  236.     // or an FW_CString255 was constructed. It used to allocate a heap-based
  237.     // representation object, and then initialize that object to reference the
  238.     // stack based buffer associated with the bound string. This function is not
  239.     // called by parts built with ODF Release 3 or later. If a part built with ODF
  240.     // Release 2 or earlier calls this method, it will be given a reference to the
  241.     // empty string, and will behave appropriately.
  242. FW_UNUSED(buffer);
  243. FW_UNUSED(bufferLen);
  244.  
  245.     return ::FW_PrivString_AcquireEmptyString();
  246. }
  247.  
  248. //----------------------------------------------------------------------------------------
  249. //    FW_PrivString_ReleaseStaticBuffer
  250. //----------------------------------------------------------------------------------------
  251.  
  252. void FW_PrivString_ReleaseStaticBuffer(FW_HString self, FW_PlatformError* error)
  253. {
  254. #ifndef FW_DEBUG
  255.     FW_UNUSED(self);
  256. #endif
  257.     // This function is obsolete and is here for compatibility with parts compiled
  258.     // with ODF Release 1 or Release 2. This function was called when an FW_CString32
  259.     // or an FW_CString255 was destructed. It was the responsibility of this function
  260.     // to determine if the stack-based buffer associated with one of the bound string
  261.     // classes was also in use by another string and, if it was, to move the stack-
  262.     // based buffer into the heap to prevent dangling pointers.  Bound strings were
  263.     // obsoleted in ODF 3 and, consequently, this function is not called by parts
  264.     // compiled with ODF 3 or later. It's behavior is correct, though, for parts
  265.     // built with ODF 1 or 2.
  266.     
  267.     *error = 0;
  268.     FW_CHECK(self);
  269. }
  270.  
  271. //----------------------------------------------------------------------------------------
  272. //    FW_PrivString_LockString
  273. //----------------------------------------------------------------------------------------
  274.  
  275. FW_HString FW_PrivString_LockString(FW_HString self, FW_PlatformError* error)
  276. {
  277.     FW_HString rep = self;
  278.     if (!rep->fLocked)
  279.     {
  280.         rep = ::StringRep_Clone(rep, error);
  281.         if (*error != 0)
  282.             return 0;
  283.         rep->fLocked = true;
  284.         rep->fRefCount = 0;
  285.     }
  286.     return rep;
  287. }
  288.  
  289. //----------------------------------------------------------------------------------------
  290. //    FW_PrivString_AcquireEmptyString
  291. //----------------------------------------------------------------------------------------
  292.  
  293. FW_HString FW_PrivString_AcquireEmptyString()
  294. {
  295.     FW_HString rep = &gEmptyStringRep;
  296.     ::FW_PrivString_Acquire(rep);
  297.     return rep;
  298. }
  299.  
  300. //----------------------------------------------------------------------------------------
  301. //    FW_PrivString_AcquireEmptyStringWithLocale
  302. //----------------------------------------------------------------------------------------
  303.  
  304. FW_HString FW_PrivString_AcquireEmptyStringWithLocale(FW_Locale locale, FW_PlatformError* error)
  305. {
  306.     FW_HString rep = &gEmptyStringRep;
  307.     ::FW_PrivString_Acquire(rep);
  308.     rep = ::StringRep_Clone(rep, error);
  309.     if (*error != 0)
  310.         return 0;
  311.     ::FW_TextParams_SetLocale(&rep->fText, locale, &rep->fParams, error);
  312.     if (*error != 0)
  313.         return 0;
  314. #ifdef FW_DEBUG
  315.     ::FW_Check(rep, 0);
  316. #endif
  317.     return rep;
  318. }
  319.  
  320. //----------------------------------------------------------------------------------------
  321. //    FW_PrivString_Acquire
  322. //----------------------------------------------------------------------------------------
  323.  
  324. void FW_PrivString_Acquire(FW_HString self)
  325. {
  326. #ifdef FW_DEBUG
  327.     ::FW_Check(self, 0);
  328. #endif
  329.     ++self->fRefCount;
  330. }
  331.  
  332. //----------------------------------------------------------------------------------------
  333. //    FW_PrivString_Release
  334. //----------------------------------------------------------------------------------------
  335.  
  336. void FW_PrivString_Release(FW_HString self)
  337. {
  338.     FW_CHECK(self);
  339.     if(--self->fRefCount == 0)
  340.     {
  341.         if (self->fLocked)
  342.         {
  343.             self->fLocked = false;
  344.             self->fRefCount = 1;
  345.         }
  346.         else
  347.         {
  348.             FW_PrimitiveFreeBlock(self->fText.text._buffer);
  349.             FW_PrimitiveFreeBlock(self);
  350.         }
  351.     }
  352. }
  353.  
  354. //----------------------------------------------------------------------------------------
  355. //    FW_PrivString_GetByteLength
  356. //----------------------------------------------------------------------------------------
  357.  
  358. FW_ByteCount FW_PrivString_GetByteLength(FW_HString self)
  359. {
  360.     FW_CHECK(self);
  361.     return self->fParams.fTextByteLength;
  362. }
  363.  
  364. //----------------------------------------------------------------------------------------
  365. //    FW_PrivString_GetCapacity
  366. //----------------------------------------------------------------------------------------
  367.  
  368. FW_ByteCount FW_PrivString_GetCapacity(FW_HString self)
  369. {
  370.     FW_CHECK(self);
  371.     return self->fParams.fTextByteCapacity;
  372. }
  373.  
  374. //----------------------------------------------------------------------------------------
  375. //    FW_PrivString_GetCharacterLength
  376. //----------------------------------------------------------------------------------------
  377.  
  378. FW_CharacterCount FW_PrivString_GetCharacterLength(FW_HString self, FW_PlatformError* error)
  379. {
  380.     FW_CHECK(self);
  381.     FW_CharacterCount result = self->fParams.fTextByteLength;// assume singlebyte locale
  382.     if (!::FW_LocaleIsSingleByte(self->fParams.fTextLocale))
  383.     {
  384.         FW_BytePosition knownStart = 0;
  385.         FW_BytePosition position = 0;
  386.         result = 0;
  387.         while (position < self->fParams.fTextByteLength)
  388.         {
  389.             FW_Boolean isStart = ::FW_TextParams_IsCharacterStart(&self->fText, knownStart, position, error);
  390.             if (*error)
  391.                 return 0;
  392.             if (isStart)
  393.             {
  394.                 knownStart = position;
  395.                 result++;
  396.             }
  397.             position++;
  398.         }
  399.     }
  400.     return result;
  401. }
  402.  
  403. //----------------------------------------------------------------------------------------
  404. //    FW_PrivString_SetCapacity
  405. //----------------------------------------------------------------------------------------
  406. FW_HString FW_PrivString_SetCapacity(FW_HString self,
  407.                                      FW_ByteCount newCapacity, 
  408.                                      FW_PlatformError* error)
  409. {
  410.     FW_HString rep = ::StringRep_Clone(self, error);
  411.     if (*error)
  412.         return 0;
  413.  
  414.     ::FW_TextParams_SetCapacity(&rep->fText,
  415.                                 newCapacity, 
  416.                                 true,
  417.                                 &rep->fParams, 
  418.                                 error);
  419.     return rep;
  420. }
  421.  
  422. //----------------------------------------------------------------------------------------
  423. //    FW_PrivString_RevealODIText
  424. //----------------------------------------------------------------------------------------
  425.  
  426. ODIText* FW_PrivString_RevealODIText(FW_HString self)
  427. {
  428.     FW_CHECK(self);
  429.     return &self->fText;
  430. }
  431.  
  432. //----------------------------------------------------------------------------------------
  433. //    FW_PrivString_RevealBuffer
  434. //----------------------------------------------------------------------------------------
  435.  
  436. const char*    FW_PrivString_RevealBuffer(FW_HString self)
  437. {
  438.     FW_CHECK(self);
  439.     return self->fParams.fTextStart;
  440. }
  441.  
  442. //----------------------------------------------------------------------------------------
  443. //    FW_PrivString_RevealLocale
  444. //----------------------------------------------------------------------------------------
  445. FW_Locale* FW_PrivString_RevealLocale(FW_HString self)
  446. {
  447.     FW_CHECK(self);
  448.     return &self->fParams.fTextLocale;
  449. }
  450.  
  451. //----------------------------------------------------------------------------------------
  452. //    FW_PrivString_GetLocale
  453. //----------------------------------------------------------------------------------------
  454.  
  455. void FW_PrivString_GetLocale(FW_HString self, FW_Locale* locale)
  456. {
  457.     FW_CHECK(self);
  458.     *locale = self->fParams.fTextLocale;
  459. }
  460.  
  461. //----------------------------------------------------------------------------------------
  462. //    FW_PrivString_Retrieve
  463. //----------------------------------------------------------------------------------------
  464.  
  465. void FW_PrivString_Retrieve(FW_HString self, 
  466.             char* destination, 
  467.             FW_ByteCount numberBytes, 
  468.             FW_BytePosition position)
  469.  
  470. {
  471.     FW_CHECK(self);
  472.     ::FW_PrimitiveCopyMemory(self->fParams.fTextStart+position, destination, numberBytes);
  473. }
  474.  
  475. //----------------------------------------------------------------------------------------
  476. //    FW_PrivString_Delete
  477. //----------------------------------------------------------------------------------------
  478.  
  479. FW_HString FW_PrivString_Delete(FW_HString self, 
  480.                                 FW_ByteCount numberBytes, 
  481.                                 FW_BytePosition position, 
  482.                                 FW_PlatformError* error)
  483. {
  484.     FW_HString rep = ::StringRep_Clone(self, error);
  485.     if (*error)
  486.         return 0;
  487.  
  488.     ::FW_PrimitiveCopyMemory(rep->fParams.fTextStart+position+numberBytes, 
  489.                             rep->fParams.fTextStart+position, 
  490.                             rep->fParams.fTextByteLength-position-numberBytes);
  491.  
  492.     ::FW_TextParams_SetLength(&rep->fText, 
  493.                             rep->fParams.fTextByteLength-numberBytes, 
  494.                             &rep->fParams, error);
  495.     if (*error)
  496.         return 0;
  497.  
  498.     return rep;
  499. }
  500.  
  501. //----------------------------------------------------------------------------------------
  502. //    FW_PrivString_Truncate
  503. //----------------------------------------------------------------------------------------
  504.  
  505. FW_HString FW_PrivString_Truncate(FW_HString self, 
  506.                                 FW_BytePosition position, 
  507.                                 FW_PlatformError* error)
  508. {
  509.     FW_HString rep = ::StringRep_Clone(self, error);
  510.     if (*error)
  511.         return 0;
  512.  
  513.     FW_PRIV_ASSERT(position>=0);
  514.     FW_PRIV_ASSERT(position<=rep->fParams.fTextByteLength);
  515.     
  516.     ::FW_TextParams_SetLength(&rep->fText, position, &rep->fParams, error);
  517.     if (*error)
  518.         return 0;
  519.  
  520.     return rep;
  521. }
  522.  
  523. //----------------------------------------------------------------------------------------
  524. //    FW_PrivString_InsertBytes
  525. //----------------------------------------------------------------------------------------
  526.  
  527. FW_HString FW_PrivString_InsertBytes(FW_HString self, 
  528.                                 const char* bytes, 
  529.                                 FW_ByteCount numberBytes,  
  530.                                 FW_BytePosition position, 
  531.                                 FW_PlatformError* error)
  532. {
  533.     FW_HString rep = ::StringRep_Clone(self, error);
  534.     CHECK_ERROR;
  535.  
  536.     FW_PRIV_ASSERT(bytes);
  537.     FW_PRIV_ASSERT(numberBytes>=0);
  538.     FW_PRIV_ASSERT(position>=0);
  539.     FW_PRIV_ASSERT(position<=rep->fParams.fTextByteLength);
  540.  
  541.     // ensure string will have sufficient capacity
  542.     ::FW_TextParams_SetCapacity(&rep->fText, 
  543.                             rep->fParams.fTextByteLength+numberBytes, 
  544.                             true,
  545.                             &rep->fParams, error);
  546.     CHECK_ERROR;
  547.     FW_PRIV_ASSERT(rep->fParams.fTextByteLength+numberBytes 
  548.                     <= rep->fParams.fTextByteCapacity);
  549.  
  550.     // move end of string to new position and make room for insertion
  551.     ::FW_PrimitiveCopyMemory(rep->fParams.fTextStart+position, 
  552.                             rep->fParams.fTextStart+position+numberBytes, 
  553.                             rep->fParams.fTextByteLength-position);
  554.  
  555.     // insert bytes into position in rep
  556.     ::FW_PrimitiveCopyMemory(bytes, 
  557.                             rep->fParams.fTextStart+position, 
  558.                             numberBytes);
  559.  
  560.     // update for the new length
  561.     ::FW_TextParams_SetLength(&rep->fText, 
  562.                             rep->fParams.fTextByteLength+numberBytes, 
  563.                             &rep->fParams, error);
  564.     CHECK_ERROR;
  565.  
  566.     return rep;
  567. }
  568.  
  569. //----------------------------------------------------------------------------------------
  570. //    FW_PrivString_InsertODIText
  571. //----------------------------------------------------------------------------------------
  572.  
  573. FW_HString FW_PrivString_InsertODIText(FW_HString self, 
  574.                                     ODIText* text, 
  575.                                     FW_BytePosition position, 
  576.                                     FW_PlatformError* error)
  577. {
  578.     // No need for FW_ERR_TRY block
  579.     FW_ODITextParams params;
  580.     ::FW_TextParams_GetParams(text, ¶ms, error);
  581.     if (*error)
  582.         return 0;
  583.  
  584.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  585.                                         params.fTextStart, 
  586.                                         params.fTextByteLength, 
  587.                                         position,
  588.                                         error);
  589.     if (*error)
  590.         return 0;
  591.     return result;
  592. }
  593.  
  594. //----------------------------------------------------------------------------------------
  595. //    FW_PrivString_InsertStringRep
  596. //----------------------------------------------------------------------------------------
  597.  
  598. FW_HString FW_PrivString_InsertStringRep(FW_HString self, 
  599.                                         FW_HString other, 
  600.                                         FW_BytePosition position, 
  601.                                         FW_PlatformError* error)
  602. {
  603.     // No need for FW_ERR_TRY block
  604.     FW_CHECK(other);
  605.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  606.                                         other->fParams.fTextStart, 
  607.                                         other->fParams.fTextByteLength, 
  608.                                         position,
  609.                                         error);
  610.     if (*error)
  611.         return 0;
  612.     return result;
  613. }
  614.  
  615. //----------------------------------------------------------------------------------------
  616. //    FW_PrivString_ReplaceAllBytes
  617. //----------------------------------------------------------------------------------------
  618.  
  619. FW_HString FW_PrivString_ReplaceAllBytes(FW_HString self,
  620.                                         const char* bytes, 
  621.                                         FW_ByteCount numberBytes, 
  622.                                         FW_PlatformError* error)
  623. {
  624.     FW_HString rep = ::StringRep_Clone(self, error);
  625.     if (*error)
  626.         return 0;
  627.  
  628.     // ensure string will have sufficient capacity
  629.     ::FW_TextParams_SetCapacity(&rep->fText,
  630.                                 numberBytes, 
  631.                                 true,
  632.                                 &rep->fParams, 
  633.                                 error);
  634.     if (*error)
  635.         return 0;
  636.  
  637.     // Copy bytes into rep
  638.     ::FW_PrimitiveCopyMemory(bytes, rep->fParams.fTextStart, numberBytes);
  639.  
  640.     // update for the new length
  641.     ::FW_TextParams_SetLength(&rep->fText, numberBytes, &rep->fParams, error);
  642.     if (*error)
  643.         return 0;
  644.  
  645.     return rep;
  646. }
  647.  
  648. //----------------------------------------------------------------------------------------
  649. //    FW_PrivString_ReplaceAllODIText
  650. //----------------------------------------------------------------------------------------
  651.  
  652. FW_HString FW_PrivString_ReplaceAllODIText(FW_HString self, 
  653.                                         ODIText* text, 
  654.                                         FW_PlatformError* error)
  655. {
  656.     // No need for FW_ERR_TRY block
  657.     FW_HString result;
  658.     
  659.     FW_ODITextParams params;
  660.     ::FW_TextParams_GetParams(text, ¶ms, error);
  661.     if (*error)
  662.         return 0;
  663.  
  664.     result = ::FW_PrivString_ReplaceAllBytes(self, 
  665.                                         params.fTextStart, 
  666.                                         params.fTextByteLength,
  667.                                         error);
  668.     if (*error)
  669.         return 0;
  670.     
  671.     ::FW_TextParams_SetLocale(&result->fText, params.fTextLocale, &result->fParams, error);
  672.  
  673.     return result;
  674. }
  675.  
  676. //----------------------------------------------------------------------------------------
  677. //    FW_PrivString_ReplaceAllStringRep
  678. //----------------------------------------------------------------------------------------
  679.  
  680. FW_HString FW_PrivString_ReplaceAllStringRep(FW_HString self, 
  681.                                         FW_HString other, 
  682.                                         FW_PlatformError* error)
  683. {
  684.     // No need for FW_ERR_TRY block
  685.     FW_HString result = self;
  686.     if (self != other)
  687.     {
  688.         if (self->fLocked)
  689.         {
  690.             result = ::FW_PrivString_ReplaceAllBytes(self, 
  691.                                                 other->fParams.fTextStart, 
  692.                                                 other->fParams.fTextByteLength,
  693.                                                 error);
  694.             if (*error)
  695.                 return 0;
  696.  
  697.             ::FW_TextParams_SetLocale(&result->fText, other->fParams.fTextLocale, &result->fParams, error);
  698.         }
  699.         else
  700.         {
  701.             ::FW_PrivString_Acquire(other);
  702.             ::FW_PrivString_Release(self);
  703.             result = other;
  704.         }
  705.     }
  706.     return result;
  707. }
  708.  
  709. //----------------------------------------------------------------------------------------
  710. //    FW_PrivString_AppendBytes
  711. //----------------------------------------------------------------------------------------
  712.  
  713. FW_HString FW_PrivString_AppendBytes(FW_HString self,
  714.                                     const char* bytes, 
  715.                                     FW_ByteCount numberBytes, 
  716.                                     FW_PlatformError* error)
  717. {
  718.     // No need for FW_ERR_TRY block
  719.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  720.                                                 bytes, 
  721.                                                 numberBytes, 
  722.                                                 self->fParams.fTextByteLength,
  723.                                                 error);
  724.     CHECK_ERROR;
  725.     return result;
  726. }
  727.  
  728. //----------------------------------------------------------------------------------------
  729. //    FW_PrivString_AppendODIText
  730. //----------------------------------------------------------------------------------------
  731.  
  732. FW_HString FW_PrivString_AppendODIText(FW_HString self, 
  733.                                     ODIText* text, 
  734.                                     FW_PlatformError* error)
  735. {
  736.     // No need for FW_ERR_TRY block
  737.     FW_HString result = ::FW_PrivString_InsertODIText(self, 
  738.                                                     text, 
  739.                                                     self->fParams.fTextByteLength, 
  740.                                                     error);
  741.     CHECK_ERROR;
  742.     return result;
  743. }
  744.  
  745. //----------------------------------------------------------------------------------------
  746. //    FW_PrivString_AppendStringRep
  747. //----------------------------------------------------------------------------------------
  748.  
  749. FW_HString FW_PrivString_AppendStringRep(FW_HString self, 
  750.                                         FW_HString other, 
  751.                                         FW_PlatformError* error)
  752. {
  753.     // No need for FW_ERR_TRY block
  754.     FW_HString result = ::FW_PrivString_InsertStringRep(self, 
  755.                                         other, 
  756.                                         self->fParams.fTextByteLength, 
  757.                                         error);
  758.     if (*error)
  759.         return 0;
  760.     return result;
  761. }
  762.  
  763. //----------------------------------------------------------------------------------------
  764. //    FW_PrivString_PrependBytes
  765. //----------------------------------------------------------------------------------------
  766.  
  767. FW_HString FW_PrivString_PrependBytes(FW_HString self,
  768.                                     const char* bytes, 
  769.                                     FW_ByteCount numberBytes, 
  770.                                     FW_PlatformError* error)
  771. {
  772.     // No need for FW_ERR_TRY block
  773.     FW_HString result = ::FW_PrivString_InsertBytes(self, bytes, numberBytes, 0, error);
  774.     if (*error)
  775.         return 0;
  776.     return result;
  777. }
  778.  
  779. //----------------------------------------------------------------------------------------
  780. //    FW_PrivString_PrependODIText
  781. //----------------------------------------------------------------------------------------
  782.  
  783. FW_HString FW_PrivString_PrependODIText(FW_HString self, 
  784.                                         ODIText* text, 
  785.                                         FW_PlatformError* error)
  786. {
  787.     // No need for FW_ERR_TRY block
  788.     FW_HString result = ::FW_PrivString_InsertODIText(self, text, 0, error);
  789.     if (*error)
  790.         return 0;
  791.     return result;
  792. }
  793.  
  794. //----------------------------------------------------------------------------------------
  795. //    FW_PrivString_PrependStringRep
  796. //----------------------------------------------------------------------------------------
  797.  
  798. FW_HString FW_PrivString_PrependStringRep(FW_HString self, 
  799.                                         FW_HString other, 
  800.                                         FW_PlatformError* error)
  801. {
  802.     // No need for FW_ERR_TRY block
  803.     FW_HString result = ::FW_PrivString_InsertStringRep(self, other, 0, error);
  804.     if (*error)
  805.         return 0;
  806.     return result;
  807. }
  808.  
  809. //----------------------------------------------------------------------------------------
  810. //    FW_PrivString_ExportCString
  811. //----------------------------------------------------------------------------------------
  812.  
  813. void FW_PrivString_ExportCString(FW_HString self, char* buffer)
  814. {
  815.     const char nul = 0;
  816.     ::FW_PrivString_Retrieve(self, buffer, self->fParams.fTextByteLength, 0);
  817.     buffer[self->fParams.fTextByteLength] = nul;
  818. }
  819.  
  820. //----------------------------------------------------------------------------------------
  821. //    FW_PrivString_ExportPascalString
  822. //----------------------------------------------------------------------------------------
  823.  
  824. void FW_PrivString_ExportPascalString(FW_HString self, FW_PascalChar* buffer)
  825. {
  826.     ::FW_PrivString_Retrieve(self, (char*)buffer+1, self->fParams.fTextByteLength, 0);
  827.     buffer[0] = FW_PascalChar(self->fParams.fTextByteLength);
  828. }
  829.  
  830. //----------------------------------------------------------------------------------------
  831. //    FW_PrivString_ToUpper
  832. //----------------------------------------------------------------------------------------
  833.  
  834. FW_HString FW_PrivString_ToUpper(FW_HString self, FW_PlatformError* error)
  835. {
  836.     FW_HString rep = ::StringRep_Clone(self, error);
  837.     if (*error)
  838.         return 0;
  839. #ifdef FW_BUILD_MAC
  840.     ::UppercaseText(rep->fParams.fTextStart, 
  841.                     rep->fParams.fTextByteLength, 
  842.                     rep->fParams.fTextLocale.fScriptCode);
  843.     *error = ::ResError();
  844.     if (*error)
  845.         return 0;
  846. #elif defined FW_BUILD_WIN
  847.     //??? Need an international implementation for windows
  848.     for (int i=0; i<rep->fParams.fTextByteLength; i++)
  849.         rep->fParams.fTextStart[i] = toupper(rep->fParams.fTextStart[i]);
  850. #endif
  851.     return rep;
  852. }
  853.  
  854. //----------------------------------------------------------------------------------------
  855. //    FW_PrivString_ToLower
  856. //----------------------------------------------------------------------------------------
  857.  
  858. FW_HString FW_PrivString_ToLower(FW_HString self, FW_PlatformError* error)
  859. {
  860.     FW_HString rep = ::StringRep_Clone(self, error);
  861.     if (*error)
  862.         return 0;
  863. #ifdef FW_BUILD_MAC
  864.     ::LowercaseText(rep->fParams.fTextStart, 
  865.                     rep->fParams.fTextByteLength, 
  866.                     rep->fParams.fTextLocale.fScriptCode);
  867.     *error = ::ResError();
  868.     if (*error)
  869.         return 0;
  870. #elif defined FW_BUILD_WIN
  871.     //??? Need an international implementation for windows
  872.     for (int i=0; i<rep->fParams.fTextByteLength; i++)
  873.         rep->fParams.fTextStart[i] = tolower(rep->fParams.fTextStart[i]);
  874. #endif
  875.     return rep;
  876. }
  877.  
  878. //----------------------------------------------------------------------------------------
  879. //    RabinKarpSearch
  880. //
  881. // Reference: Introduction to Algorithms, By Corment, Leiserson & Rivest, page 860
  882. // Note: The standard library function strstr is possibly as efficient as RabinKarpSearch,
  883. // but unfortunately it assumes that both strings are NUL terminated ISO strings.  ODIText
  884. // data structures are not necessarily NUL terminated, so we can't use strstr.  Note also
  885. // that there are algorithms more efficient than Rabin-Karp, but they're more complicated
  886. // to implement, and unlikely to be significantly better than Rabin-Karp for most common
  887. // string searching tasks.  Developers creating text engines will probably keep their text
  888. // in some other kind of data structure and will have their own searching functions.
  889. //----------------------------------------------------------------------------------------
  890.  
  891. static unsigned long RadixPower(unsigned long radix, 
  892.                                 unsigned long power, 
  893.                                 unsigned long modulus)
  894. {
  895.     unsigned long result = 1;
  896.     while (--power > 0)
  897.         result = (result * radix) % modulus;
  898.     return result;
  899. }
  900.  
  901. class CPrivCharIterator
  902. {
  903. public:
  904.     CPrivCharIterator() {}
  905.     CPrivCharIterator(const unsigned char* pos, int delta) : fPos(pos), fDelta(delta) {}
  906.     CPrivCharIterator(const CPrivCharIterator& other) : fPos(other.fPos), fDelta(other.fDelta) {}
  907.     void operator++() { fPos += fDelta; }
  908.     operator const unsigned char*() const { return fPos; }
  909.     int operator==(const CPrivCharIterator& other) const { return fPos==other.fPos; }
  910.     int operator!=(const CPrivCharIterator& other) const { return fPos!=other.fPos; }
  911.     void operator=(const CPrivCharIterator& other) { fPos=other.fPos; fDelta=other.fDelta; }
  912.     unsigned char operator*() const { return *fPos; }
  913.     
  914. private:
  915.     const unsigned char* fPos;
  916.     int fDelta;
  917. };
  918.  
  919. const unsigned long kRadix = 256;
  920. const unsigned long kModulus = (1L<<24) - 3;    // this is the largest prime less than 2**24
  921.  
  922. static unsigned long RunValue(CPrivCharIterator& begin, CPrivCharIterator& limit)
  923. {
  924.     unsigned long value = 0;
  925.     CPrivCharIterator i;
  926.     for (i=begin; i!=limit; ++i)
  927.     {
  928.         unsigned char c = *i;
  929.         value = (kRadix*value + c) % kModulus;
  930.     }
  931.     return value;
  932. }
  933.  
  934. static int PrivCompare(const CPrivCharIterator& pat, 
  935.                         const CPrivCharIterator& window, 
  936.                         const CPrivCharIterator& patLimit)
  937. {
  938.     CPrivCharIterator i=pat;
  939.     CPrivCharIterator w=window;
  940.     
  941.     while (i!=patLimit)
  942.     {
  943.         if (*i != *w)
  944.             return 0;
  945.         ++i;
  946.         ++w;
  947.     }
  948.     return 1;
  949. }
  950.  
  951. static long RabinKarpSearch(const unsigned char* text, 
  952.                             const unsigned char* pat, 
  953.                             long n, // length of text
  954.                             long m,    // length of pat
  955.                             int searchForwards = 1)
  956. {
  957.     long shift = -1;
  958.     if (m <= 0)
  959.         return shift;
  960.     if (m > n)
  961.         return shift;
  962.     
  963.     const unsigned long h = RadixPower(kRadix, m, kModulus);
  964.  
  965.     CPrivCharIterator wbegin;
  966.     CPrivCharIterator wend;
  967.     CPrivCharIterator wlimit;
  968.     CPrivCharIterator pbegin;
  969.     CPrivCharIterator pend;
  970.  
  971.     if (searchForwards)
  972.     {
  973.         wbegin = CPrivCharIterator(text, 1);
  974.         wend = CPrivCharIterator(text+m, 1);
  975.         wlimit = CPrivCharIterator(text+n-m+1, 0);
  976.         pbegin = CPrivCharIterator(pat, 1);
  977.         pend = CPrivCharIterator(pat+m, 1);
  978.     }
  979.     else
  980.     {
  981.         wbegin = CPrivCharIterator(text+n-1, -1);
  982.         wend = CPrivCharIterator(text+n-m-1, -1);
  983.         wlimit = CPrivCharIterator(text-1, 0);
  984.         pbegin = CPrivCharIterator(pat+m-1, -1);
  985.         pend = CPrivCharIterator(pat-1, -1);
  986.     }
  987.  
  988.     unsigned long p = RunValue(pbegin, pend);
  989.     unsigned long t = RunValue(wbegin, wend);
  990.  
  991.     while (wbegin != wlimit)
  992.     {
  993.         if ((p == t) && PrivCompare(pbegin, wbegin, pend))
  994.         {
  995.             shift = (const unsigned char*)wbegin - text;
  996.             break;
  997.         }
  998.  
  999.         unsigned char c = *wbegin;
  1000.         ++wbegin;
  1001.  
  1002.         if (wbegin != wlimit)
  1003.         {
  1004.             // subtract out the oldest character
  1005.             unsigned long z = (c*h) % kModulus;
  1006.             if (t >= z)
  1007.                 t -= z;
  1008.             else
  1009.                 t = t + kModulus - z;
  1010.  
  1011.             // add in the new character
  1012.             c = *wend;
  1013.             t = (kRadix*t + c) % kModulus;
  1014.  
  1015.             ++wend;
  1016.             FW_ASSERT(t == RunValue(wbegin, wend));
  1017.         }
  1018.         
  1019.     }
  1020.     
  1021.     if (shift != -1 && !searchForwards)
  1022.     {
  1023.         shift -= (m-1);
  1024.     }
  1025.     
  1026.     return shift;
  1027. }
  1028.  
  1029. //----------------------------------------------------------------------------------------
  1030. //    FW_PrivString_FindCharacter
  1031. //----------------------------------------------------------------------------------------
  1032.  
  1033. static FW_Boolean PrivIsCharacterMatch(FW_HString self, 
  1034.                                 FW_ByteCount i,
  1035.                                 FW_ByteCount *foundPosition)
  1036. {
  1037.     FW_Boolean result = false;
  1038.     FW_PlatformError error = 0;
  1039.     if (::FW_LocaleIsSingleByte(self->fParams.fTextLocale)
  1040.         || FW_TextParams_IsCharacterStart(&self->fText, 0, i, &error))
  1041.     {
  1042.         FW_ASSERT(error == 0);
  1043.         result = true;
  1044.         *foundPosition = i;
  1045.     }
  1046.     return result;
  1047. }
  1048.  
  1049. const FW_LChar kLowByteMask = 0x0FF;
  1050. const FW_LChar kLowByteAntiMask = ~kLowByteMask;
  1051.  
  1052. static void LCharToBytes(FW_LChar c, char* bytes)
  1053. {
  1054.     *bytes++ = c >> 8;
  1055.     *bytes = c & kLowByteMask;
  1056. }
  1057.  
  1058. FW_Boolean FW_PrivString_FindCharacter(FW_HString self, 
  1059.                         FW_LChar character, 
  1060.                         FW_ByteCount *foundPosition, 
  1061.                         FW_ByteCount startPosition,
  1062.                         FW_FindDirection direction)
  1063. {
  1064.     FW_Boolean result = false;    // assume failure to find character
  1065.     
  1066.     if ((character & kLowByteAntiMask) == 0)
  1067.     {
  1068.         // If the character we're searching for is a single byte character
  1069.         // then we can use a simple char-by-char scan
  1070.         register char c = (char) (character & kLowByteMask);
  1071.         register const char* text = self->fParams.fTextStart;
  1072.         if (direction == FW_kForwards)
  1073.         {
  1074.             for (FW_ByteCount i=startPosition; i<self->fParams.fTextByteLength; i++)
  1075.             {
  1076.                 if ((text[i] == c) && (result=PrivIsCharacterMatch(self, i, foundPosition)) == true)
  1077.                     break;
  1078.             }
  1079.         }
  1080.         else
  1081.         {
  1082.             for (FW_ByteCount i=startPosition; i>=0; i--)
  1083.             {
  1084.                 if ((text[i] == c) && (result=PrivIsCharacterMatch(self, i, foundPosition)) == true)
  1085.                     break;
  1086.             }
  1087.         }
  1088.     }
  1089.     else if (!::FW_LocaleIsSingleByte(self->fParams.fTextLocale))
  1090.     {
  1091.         // If we've gotten to here, we have a locale that is not single-byte,
  1092.         // and we're searching for a character that is not a single-byte character.
  1093.         // We handle that case by making a single-character string and then doing
  1094.         // a substring search.
  1095.         char bytes[2];
  1096.         LCharToBytes(character, bytes);
  1097.         *foundPosition = RabinKarpSearch((const unsigned char*)self->fParams.fTextStart+startPosition, 
  1098.                             (const unsigned char*)bytes, 
  1099.                             self->fParams.fTextByteLength-startPosition,
  1100.                             2,    // length of pat
  1101.                             direction == FW_kForwards);
  1102.         result = *foundPosition != -1;
  1103.         if (result)
  1104.         {
  1105.             *foundPosition += startPosition;
  1106.         }
  1107.     }
  1108.     else
  1109.     {
  1110.         // If we've gotten to here, we're trying to find a multi-byte character
  1111.         // in a single-byte locale string. By definition, that must fail, right?
  1112.         // Since result is already set to false, we don't have to do anything.
  1113.     }
  1114.     return result;
  1115. }
  1116.  
  1117. //----------------------------------------------------------------------------------------
  1118. //    FW_PrivString_FindSubString
  1119. //----------------------------------------------------------------------------------------
  1120.  
  1121. FW_Boolean FW_PrivString_FindSubString(FW_HString self, 
  1122.                         FW_HString subString, 
  1123.                         FW_ByteCount *foundPosition, 
  1124.                         FW_ByteCount startPosition)
  1125. {
  1126.     *foundPosition = RabinKarpSearch((const unsigned char*) self->fParams.fTextStart+startPosition,
  1127.                                 (const unsigned char*) subString->fParams.fTextStart,
  1128.                                 self->fParams.fTextByteLength-startPosition,
  1129.                                 subString->fParams.fTextByteLength);
  1130.     if (*foundPosition != -1)
  1131.         *foundPosition += startPosition;
  1132.     return (*foundPosition != -1);
  1133. }
  1134.  
  1135. //----------------------------------------------------------------------------------------
  1136. //    FW_PrivString_Substitute
  1137. //----------------------------------------------------------------------------------------
  1138.  
  1139. FW_HString FW_PrivString_Substitute(FW_HString self, 
  1140.                         FW_HString searchString, 
  1141.                         FW_HString substitutionString, 
  1142.                         FW_Boolean* wasReplaced, 
  1143.                         FW_PlatformError* error)
  1144. {
  1145.     FW_HString rep = self;
  1146.     FW_ByteCount foundPosition;
  1147.     *wasReplaced = false;
  1148.     if (::FW_PrivString_FindSubString(self, searchString, &foundPosition, 0))
  1149.     {
  1150.         FW_HString temp;
  1151.         rep = ::StringRep_Clone(self, error);
  1152.         temp = ::FW_PrivString_Delete(rep, 
  1153.                                     FW_PrivString_GetByteLength(searchString), 
  1154.                                     foundPosition,
  1155.                                     error);
  1156.         if (*error)
  1157.             return 0;
  1158.         FW_PRIV_ASSERT(temp == rep);
  1159.         temp = ::FW_PrivString_InsertStringRep(rep, 
  1160.                                         substitutionString, 
  1161.                                         foundPosition, 
  1162.                                         error);
  1163.         if (*error)
  1164.             return 0;
  1165.         FW_PRIV_ASSERT(temp == rep);
  1166.         *wasReplaced = true;
  1167.     }
  1168.     return rep;
  1169. }
  1170.  
  1171. //----------------------------------------------------------------------------------------
  1172. //    Comparison Functions
  1173. //----------------------------------------------------------------------------------------
  1174. //----------------------------------------------------------------------------------------
  1175. //    FW_TextCompare - compares two (ASCII) text buffers
  1176. //----------------------------------------------------------------------------------------
  1177.  
  1178. static FW_StringCompareResult FW_TextCompare(const char* p1, FW_ByteCount len1,
  1179.                                              const char* p2, FW_ByteCount len2)
  1180. {
  1181.     FW_ByteCount len = len1;
  1182.     FW_StringCompareResult result = FW_kStringsEqual;     // assume strings are equal
  1183.     if (len1 < len2)
  1184.         result = FW_kStringOneLess;            // now assume string 1 is less because it's shorter
  1185.     else if (len1 > len2)
  1186.     {
  1187.         result = FW_kStringOneGreater;        // now assume string 1 is greater because it's longer
  1188.         len = len2;
  1189.     }
  1190.     
  1191.     const unsigned char* s1 = (const unsigned char*) p1;
  1192.     const unsigned char* s2 = (const unsigned char*) p2;
  1193.     unsigned char c1;
  1194.     unsigned char c2;
  1195.  
  1196.     while (len > 0)
  1197.     {
  1198.         c1 = *s1++;
  1199.         c2 = *s2++;
  1200.         if (c1 != c2)
  1201.             break;
  1202.         len--;
  1203.     }
  1204.     
  1205.     if (len > 0)
  1206.     {
  1207.         if (c1 < c2)
  1208.             result = FW_kStringOneLess;
  1209.         if (c1 > c2)
  1210.             result = FW_kStringOneGreater;
  1211.     }
  1212.         
  1213.     return result;
  1214. }
  1215.  
  1216. //----------------------------------------------------------------------------------------
  1217. //    FW_PrivString_Compare
  1218. //----------------------------------------------------------------------------------------
  1219.  
  1220. FW_StringCompareResult FW_PrivString_Compare(FW_HString string1, FW_HString string2)
  1221. {
  1222. #ifdef FW_BUILD_MAC
  1223.     if (FW_PrivString_CompareLocale(string1, string2))
  1224.     {
  1225.         return ::TextOrder(string1->fParams.fTextStart, 
  1226.                             string2->fParams.fTextStart, 
  1227.                             string1->fParams.fTextByteLength, 
  1228.                             string2->fParams.fTextByteLength, 
  1229.                             string1->fParams.fTextLocale.fScriptCode, 
  1230.                             string2->fParams.fTextLocale.fScriptCode, 
  1231.                             string1->fParams.fTextLocale.fLangCode, 
  1232.                             string2->fParams.fTextLocale.fLangCode);
  1233.     }
  1234.     // If locales are different, compare only the characters
  1235.     return FW_TextCompare(string1->fParams.fTextStart, 
  1236.                           string1->fParams.fTextByteLength, 
  1237.                           string2->fParams.fTextStart, 
  1238.                           string2->fParams.fTextByteLength);
  1239. #else
  1240.     // [MEB] For now just compare text; 
  1241.     // need to find or write a Windows string comparison routine
  1242.     return FW_TextCompare(string1->fParams.fTextStart, 
  1243.                           string1->fParams.fTextByteLength, 
  1244.                           string2->fParams.fTextStart, 
  1245.                           string2->fParams.fTextByteLength);
  1246. #endif
  1247. }
  1248.  
  1249. //----------------------------------------------------------------------------------------
  1250. //    FW_PrivString_CompareLocale
  1251. //----------------------------------------------------------------------------------------
  1252. FW_Boolean FW_PrivString_CompareLocale(FW_HString string1, FW_HString string2)
  1253. {
  1254.     if (string1->fParams.fTextLocale.fScriptCode != string2->fParams.fTextLocale.fScriptCode)
  1255.         return false;
  1256.     return (string1->fParams.fTextLocale.fLangCode == string2->fParams.fTextLocale.fLangCode);
  1257. }
  1258.  
  1259. //----------------------------------------------------------------------------------------
  1260. //    Number Conversion Functions
  1261. //----------------------------------------------------------------------------------------
  1262.  
  1263. //----------------------------------------------------------------------------------------
  1264. //    FW_PrivString_SignedIntegerToDecimalString
  1265. //----------------------------------------------------------------------------------------
  1266.  
  1267. FW_HString FW_PrivString_SignedIntegerToDecimalString(FW_HString self, 
  1268.                                                     long integer, 
  1269.                                                     FW_PlatformError* error)
  1270. {
  1271.     // we allow for the possiblity that longs are more than 32 bits
  1272.     const int kMaxDigits = 32;
  1273.     char string[kMaxDigits];
  1274.     FW_Boolean negative = integer < 0;
  1275.     if (negative) 
  1276.         integer = -integer;
  1277.     const char kZero = '0';
  1278.     const long int kBase = 10;
  1279.         
  1280.     int i = kMaxDigits;
  1281.  
  1282.     if (integer == 0)
  1283.     {
  1284.         --i;
  1285.         string[i] = kZero;
  1286.     }
  1287.     else
  1288.     {
  1289.         while (integer > 0)
  1290.         {
  1291.             --i;
  1292.             string[i] = (char) (integer % kBase) + kZero;
  1293.             integer = integer / kBase;
  1294.         }
  1295.     }
  1296.     
  1297.     if (negative)
  1298.     {
  1299.         --i;
  1300.         string[i] = '-';
  1301.     }
  1302.     
  1303.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1304. }
  1305.  
  1306. //----------------------------------------------------------------------------------------
  1307. //    FW_PrivString_UnsignedIntegerToDecimalString
  1308. //----------------------------------------------------------------------------------------
  1309.  
  1310. FW_HString FW_PrivString_UnsignedIntegerToDecimalString(FW_HString self, 
  1311.                                                     unsigned long integer, 
  1312.                                                     FW_PlatformError* error)
  1313. {
  1314.     // we allow for the possiblity that longs are more than 32 bits
  1315.     const int kMaxDigits = 32;
  1316.     char string[kMaxDigits];
  1317.     const char kZero = '0';
  1318.     const long int kBase = 10;
  1319.         
  1320.     int i = kMaxDigits;
  1321.  
  1322.     if (integer == 0)
  1323.     {
  1324.         --i;
  1325.         string[i] = kZero;
  1326.     }
  1327.     else
  1328.     {
  1329.         while (integer > 0)
  1330.         {
  1331.             --i;
  1332.             string[i] = (char) (integer % kBase) + kZero;
  1333.             integer = integer / kBase;
  1334.         }
  1335.     }
  1336.     
  1337.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1338. }
  1339.  
  1340. //----------------------------------------------------------------------------------------
  1341. //    FW_PrivString_UnsignedIntegerToHexadecimalString
  1342. //----------------------------------------------------------------------------------------
  1343.  
  1344. FW_HString FW_PrivString_UnsignedIntegerToHexadecimalString(FW_HString self, 
  1345.                                                     unsigned long integer, 
  1346.                                                     FW_PlatformError* error)
  1347. {
  1348.     // we allow for the possiblity that longs are more than 32 bits
  1349.     const int kMaxDigits = 32;
  1350.     char string[kMaxDigits];
  1351.     const char kZero = '0';
  1352.     const char kA = 'A' - 10;
  1353.     const long int kBase = 16;
  1354.         
  1355.     int i = kMaxDigits;
  1356.  
  1357.     if (integer == 0)
  1358.     {
  1359.         --i;
  1360.         string[i] = kZero;
  1361.     }
  1362.     else
  1363.     {
  1364.         while (integer > 0)
  1365.         {
  1366.             --i;
  1367.             unsigned long digit = (integer % kBase);
  1368.             if (digit < 10)
  1369.                 string[i] = (char) digit + kZero;
  1370.             else
  1371.                 string[i] = (char) digit + kA;
  1372.             integer = integer / kBase;
  1373.         }
  1374.     }
  1375.     
  1376.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1377. }
  1378.  
  1379. //----------------------------------------------------------------------------------------
  1380. //    FW_PrivString_DecimalStringToSignedInteger
  1381. //----------------------------------------------------------------------------------------
  1382.  
  1383. long FW_PrivString_DecimalStringToSignedInteger_Valid(FW_HString self,
  1384.                                                     FW_Boolean* wasValid)
  1385. {
  1386.     FW_ASSERT(wasValid);
  1387.     
  1388.     const char* string = self->fParams.fTextStart;
  1389.     const char* last = string + self->fParams.fTextByteLength;
  1390.     FW_Boolean negative = (*string == '-');
  1391.     const char kZero = '0';
  1392.     const char kNine = '9';
  1393.     const long int kBase = 10;
  1394.     long result = 0;
  1395.     register FW_Boolean charGood = true;
  1396.  
  1397.     if (negative)
  1398.         ++string;
  1399.     
  1400.     const char* startString = string;
  1401.  
  1402.     while ((string < last) && charGood)
  1403.     {
  1404.         char curChar = *string;
  1405.         charGood = ((curChar >= kZero) && (curChar <= kNine));
  1406.         if (charGood)
  1407.         {
  1408.             long digit = curChar - kZero;
  1409.             result = result*kBase + digit;
  1410.             ++string;
  1411.         }
  1412.     }
  1413.         
  1414.     if (negative)
  1415.         result = -result;
  1416.     
  1417.     *wasValid = (charGood && (string > startString));
  1418.     
  1419.     return result;
  1420. }
  1421.  
  1422. //----------------------------------------------------------------------------------------
  1423. //    FW_PrivString_DecimalStringToSignedInteger
  1424. //----------------------------------------------------------------------------------------
  1425.  
  1426. long FW_PrivString_DecimalStringToSignedInteger(FW_HString self)
  1427. {
  1428.     FW_Boolean wasValid;
  1429.     return FW_PrivString_DecimalStringToSignedInteger_Valid(self, &wasValid);
  1430. }
  1431.  
  1432. //----------------------------------------------------------------------------------------
  1433. //    FW_PrivString_DecimalStringToUnsignedInteger
  1434. //----------------------------------------------------------------------------------------
  1435.  
  1436. unsigned long FW_PrivString_DecimalStringToUnsignedInteger_Valid(FW_HString self,
  1437.                                                                 FW_Boolean* wasValid)
  1438. {
  1439.     const char* string = self->fParams.fTextStart;
  1440.     const char* last = string + self->fParams.fTextByteLength;
  1441.     const char kZero = '0';
  1442.     const char kNine = '9';
  1443.     const unsigned long int kBase = 10;
  1444.     unsigned long result = 0;
  1445.     register FW_Boolean charGood = true;
  1446.  
  1447.     while ((string<last) && charGood)
  1448.     {
  1449.         char curChar = *string;
  1450.         charGood = ((curChar >= kZero) && (curChar <= kNine));
  1451.         if (charGood)
  1452.         {
  1453.             unsigned long digit = curChar - kZero;
  1454.             result = result*kBase + digit;
  1455.             ++string;
  1456.         }
  1457.     }
  1458.  
  1459.     *wasValid = (charGood && (string > self->fParams.fTextStart));
  1460.     
  1461.     return result;
  1462. }
  1463.  
  1464. //----------------------------------------------------------------------------------------
  1465. //    FW_PrivString_DecimalStringToUnsignedInteger
  1466. //----------------------------------------------------------------------------------------
  1467.  
  1468. unsigned long FW_PrivString_DecimalStringToUnsignedInteger(FW_HString self)
  1469. {
  1470.     FW_Boolean wasValid;
  1471.     return FW_PrivString_DecimalStringToUnsignedInteger_Valid(self, &wasValid);
  1472. }
  1473.  
  1474. //----------------------------------------------------------------------------------------
  1475. //    IsHex
  1476. //----------------------------------------------------------------------------------------
  1477.  
  1478. static FW_Boolean IsHex(const char hexChar, unsigned long& digit)
  1479. {
  1480.     FW_Boolean result = false;
  1481.     if (hexChar>='0' && hexChar<='9')
  1482.     {
  1483.         result = true;
  1484.         digit = hexChar - '0';
  1485.     }
  1486.     else if (hexChar>='a' && hexChar<='f')
  1487.     {
  1488.         result = true;
  1489.         digit = hexChar - 'a' + 10;
  1490.     }
  1491.     else if (hexChar>='A' && hexChar<='F')
  1492.     {
  1493.         result = true;
  1494.         digit = hexChar - 'A' + 10;
  1495.     }
  1496.     return result;
  1497. }
  1498.  
  1499. //----------------------------------------------------------------------------------------
  1500. //    FW_PrivString_HexadecimalStringToUnsignedInteger
  1501. //----------------------------------------------------------------------------------------
  1502.  
  1503. unsigned long FW_PrivString_HexadecimalStringToUnsignedInteger_Valid(FW_HString self,
  1504.                                                                     FW_Boolean* wasValid)
  1505. {
  1506.     const char* string = self->fParams.fTextStart;
  1507.     const char* last = string + self->fParams.fTextByteLength;
  1508.     const unsigned long int kBase = 16;
  1509.     unsigned long result = 0;
  1510.     unsigned long digit;
  1511.     register FW_Boolean charGood = true;
  1512.  
  1513.     while ((string<last) && charGood)
  1514.     {
  1515.         charGood = IsHex(*string, digit);
  1516.         if (charGood)
  1517.         {
  1518.             result = result*kBase + digit;
  1519.             ++string;
  1520.         }
  1521.     }
  1522.     *wasValid = (charGood && (string > self->fParams.fTextStart));
  1523.     return result;
  1524. }
  1525.  
  1526. //----------------------------------------------------------------------------------------
  1527. //    FW_PrivString_HexadecimalStringToUnsignedInteger
  1528. //----------------------------------------------------------------------------------------
  1529.  
  1530. unsigned long FW_PrivString_HexadecimalStringToUnsignedInteger(FW_HString self)
  1531. {
  1532.     FW_Boolean wasValid;
  1533.     return FW_PrivString_HexadecimalStringToUnsignedInteger_Valid(self, &wasValid);
  1534. }
  1535.  
  1536. //----------------------------------------------------------------------------------------
  1537. //    FW_PrivString_DoubleToString
  1538. //----------------------------------------------------------------------------------------
  1539.  
  1540. FW_HString FW_PrivString_DoubleToString(FW_HString self, 
  1541.                                         double value, 
  1542.                                         short fractionalDigits, 
  1543.                                         FW_PlatformError* error)
  1544. {
  1545. #ifdef FW_BUILD_MAC
  1546.     decform form = {FIXEDDECIMAL, 0, fractionalDigits};
  1547.     decimal intermediate;
  1548.     char buffer[DECSTROUTLEN];
  1549.     
  1550.     num2dec(&form, value, &intermediate);
  1551.     dec2str(&form, &intermediate, buffer);
  1552.     
  1553.     return ::FW_PrivString_ReplaceAllBytes(self, 
  1554.                                         buffer, 
  1555.                                         FW_PrimitiveStringLength(buffer), 
  1556.                                         error);
  1557. #elif defined FW_BUILD_WIN
  1558.     FW_PRIV_ASSERT(Not_Yet_Implemented);
  1559.     return (FW_HString) NULL;
  1560. #endif
  1561. }
  1562.  
  1563. //----------------------------------------------------------------------------------------
  1564. //    FW_PrivString_StringToDouble
  1565. //----------------------------------------------------------------------------------------
  1566.  
  1567. double FW_PrivString_StringToDouble_Valid(FW_HString self,
  1568.                                         FW_Boolean* wasValid)
  1569. {
  1570.     double result = 0;
  1571.     
  1572. #if defined FW_BUILD_MAC
  1573.     // See IM-PPC Numerics for documentation on str2dec (chap 9, "Conversion Functions")
  1574.     decimal intermediate;        // On return, a pointer to the decimal structure containing the decimal number.
  1575.     short ix = 0;                // On entry, the starting position in the string. 
  1576.                                 // On return, one greater than the position of the last character in the 
  1577.                                 // string that was parsed if the entire string was not converted successfully.
  1578.     short vp;                    // On return, a Boolean argument indicating the success of the function. 
  1579.                                 // If the entire string was parsed, vp is true. If part of the string was parsed, 
  1580.                                 // vp is false and ix indicates where the function stopped parsing.
  1581.     char buffer[256];
  1582.     FW_PrivString_ExportCString(self, buffer);
  1583.     str2dec(buffer, &ix, &intermediate, &vp);
  1584.     result = dec2num(&intermediate);
  1585.     *wasValid = (vp != 0);
  1586. #elif defined FW_BUILD_WIN
  1587.     FW_PRIV_ASSERT(Not_Yet_Implemented);
  1588. #endif
  1589.  
  1590.     return result;
  1591. }
  1592.  
  1593. //----------------------------------------------------------------------------------------
  1594. //    FW_PrivString_StringToDouble
  1595. //----------------------------------------------------------------------------------------
  1596.  
  1597. double FW_PrivString_StringToDouble(FW_HString self)
  1598. {
  1599.     FW_Boolean wasValid;
  1600.     return FW_PrivString_StringToDouble_Valid(self, &wasValid);
  1601. }
  1602.  
  1603. //----------------------------------------------------------------------------------------
  1604. //    FW_PrivString_IsValidDecimalString
  1605. //----------------------------------------------------------------------------------------
  1606. FW_Boolean FW_PrivString_IsValidDecimalString(FW_HString self, 
  1607.                                               FW_Boolean allowDecimalPoint, 
  1608.                                               FW_Boolean allowSign)
  1609. {
  1610.     const char kZero = '0';
  1611.     const char kNine = '9';
  1612.     const char kPoint = '.';
  1613.     const char kMinus = '-';
  1614.     const char kPlus = '+';
  1615.     const char* string = self->fParams.fTextStart;
  1616.     const char* last = string + self->fParams.fTextByteLength;
  1617.     FW_Boolean foundDecimal = false;    // make sure there's only one
  1618.     short count = 0;
  1619.     short maxDigits = 10;
  1620.     if (allowDecimalPoint)
  1621.         maxDigits = 16;
  1622.  
  1623.     if (allowSign)    // check the first character for a sign
  1624.     {
  1625.         if (*string == kMinus)
  1626.             ++string;
  1627.         else if ((*string == kPlus) && allowDecimalPoint)    // plus-sign only works with reals
  1628.             ++string;
  1629.     }
  1630.  
  1631.     while (string < last)
  1632.     {
  1633.         if ((*string >= kZero) && (*string <= kNine))        // valid decimal digit
  1634.         {
  1635.             count++;
  1636.             if ((count > maxDigits) && !foundDecimal)
  1637.                 return false;
  1638.         }
  1639.         else
  1640.         {
  1641.             if (allowDecimalPoint && (*string == kPoint) && !foundDecimal)
  1642.                 foundDecimal = true;
  1643.             else 
  1644.                 return false;
  1645.         }
  1646.         ++string;
  1647.     }
  1648.     return true;
  1649. }
  1650.  
  1651. //----------------------------------------------------------------------------------------
  1652. //    FW_PrivString_IsValidHexadecimalString
  1653. //----------------------------------------------------------------------------------------
  1654. FW_Boolean FW_PrivString_IsValidHexadecimalString(FW_HString self)
  1655. {
  1656.     if (self->fParams.fTextByteLength > 8)    // can't have more than 8 hex digits
  1657.         return false;
  1658.  
  1659.     const char* string = self->fParams.fTextStart;
  1660.     const char* last = string + self->fParams.fTextByteLength;
  1661.     unsigned long digit;
  1662.     while (string < last)
  1663.     {
  1664.         if (!IsHex(*string, digit))
  1665.             return false;
  1666.         ++string;
  1667.     }
  1668.     return true;
  1669. }
  1670.